/*

for each contig i = 0 ... n-1
      for each contig j=i+1....n-1
	int comparisonVal = contig[ i ].compareTo(contig[ j ]) // higher values, associated with higher similarity in content and order
	int k;
	for each contig k = i+1 …  j-1
		if( comparisonVal < contig[ i ].compareTo( contig[ j+1 ] ) //once the 
			break;
	

		
	while( comparisonVal < contig[i].compareTo(contig[j+1] )

        	if contigs are completely identical in content and order
            		swap contig j with contig i+1
       	if not identical
          //go through from i+1 to j and find where it belongs based on some measure of degree of similarity-- percent of genes in common plus percent of genes with same count

*/

public class Contig extends RectObject implements Comparable
{
  String contigSpecies;
  String contigId;
  String contigStrain;
  
  Gene[] genes;
  
  //float x1, x2, y1, y2;//static position/former position
  //Integrator dynX1, dynX2, dynY1, dynY2;//current position
  float height;
  
  //fields to control look of genes
  Integrator dynMaxNT, dynMinNT;//map gene to this max NT
  float geneHeightToTotalHeightRatio;
  float geneHeight;
  
  int genesAdded;
  
  Contig( String contigSpecies, String contigStrain, String contigId, int geneCount )
  {
    this( contigSpecies, contigStrain, contigId, geneCount, 0.0, 0.0, 0.0, 0.0, 0 );
  }
  
  Contig( String contigSpecies, String contigStrain, String contigId, int geneCount, int maxNT )
  {
    this( contigSpecies, contigStrain, contigId, geneCount, 0.0, 0.0, 0.0, 0.0, maxNT );
  }
  
  Contig( String contigSpecies, String contigStrain, String contigId, int geneCount, float x1, float y1, float x2, float y2)
  {
    this( contigSpecies, contigStrain, contigId, geneCount, x1, y1, x2, y2, 0 );
  }
  
  Contig( String contigSpecies, String contigStrain, String contigId, int geneCount, float x1, float y1, float x2, float y2, int maxNT )
  {
    super( x1, y1, x2, y2 );
    
    this.contigId = contigId;
    this.contigSpecies = contigSpecies;
    this.contigStrain = contigStrain;
    
    genes = new Gene[geneCount];
    genesAdded = 0;
    
    this.height = getY2() - getY1();
    
    this.dynMaxNT = new Integrator( (float) maxNT );
    this.dynMinNT = new Integrator( (float) 0 );
    geneHeightToTotalHeightRatio = .2;//.05;
    geneHeight = calculateGeneHeight( getY1(), getY2() );
    
    //ntMin = 0;
    //ntMax = (int) dynMaxNT.value;
  }
  
  //-------------------------------------------SETUP METHODS---------------------------------------------------
  void addGene( int start, int stop, String known, String toxinName )
  {
    if( genesAdded >= genes.length )
    {
      println( "too many genes added");
      return;
    }
    
    float gX1 = calculateGeneX1( start, stop, dynMinNT.value, dynMaxNT.value, getX1(), getX2() ); //plus 20 is for label on contig
    float gX2 = calculateGeneX2( start, stop, dynMinNT.value, dynMaxNT.value, getX1(), getX2() );  
    float gY1 = calculateGeneY1( getY1(), getY2() );
    float gY2 = calculateGeneY2( getY1(), getY2() );
    genes[ genesAdded ] = new Gene( this, gX1, gY1, gX2, gY2, start, stop, known, toxinName );
    genesAdded++;
  }
  
  float calculateGeneX1( int start, int stop, float minNTVal, float maxNTVal, float x1Val, float x2Val )
  {
    if( start < stop )
      return map( start, minNTVal, maxNTVal, x1Val, x2Val );
    return map( stop, minNTVal, maxNTVal, x1Val, x2Val );
  }
  
  float calculateGeneX2( int start, int stop, float minNTVal, float maxNTVal, float x1Val, float x2Val )
  {
    if( start < stop )
      return map( stop, minNTVal, maxNTVal, x1Val, x2Val );
    return map( start, minNTVal, maxNTVal, x1Val, x2Val );
  }
  
  float calculateGeneY1(float y1Val, float y2Val )
  {
    return (y2Val + y1Val)/2 - calculateGeneHeight( y1Val, y2Val)/2; 
  }
  
  float calculateGeneY2(float y1Val, float y2Val )
  {
    return (y2Val + y1Val)/2 + calculateGeneHeight( y1Val, y2Val)/2;
  }
  
  float calculateGeneHeight( float y1Val, float y2Val )
  {
    return geneHeightToTotalHeightRatio*(y2Val-y1Val);
  }
  //-------------------------------------------END SETUP METHODS------------------------------------------------
  //---------------------------------------------DRAW METHODS---------------------------------------------------
  void draw()
  {
    super.draw();
    
    //rect
    rectMode( CORNERS );
    noStroke();
    fill( 20, 20, 20);
    if( mouseIsOverPrecise() )
      fill( 50, 50, 50 );

    roundRect(  getX1(), getY1(), getX2(), getY2() );
  
    drawText();
    
    //genes
    for(int i = 0; i < genes.length; i++)
      genes[i].draw();
  }
  
  void drawText()
  {
    if( mouseIsOverPrecise() )
    {
      fill( 50, 50, 50, 2 );
      textSize( 18.0 );
      float w = textWidth( contigStrain );
      rect( getX1()-1-w, (getY1()+getY2())/2-10, getX1(), (getY1()+getY2())/2+10 );
      fill(255, 255, 255);
      textAlign(RIGHT, CENTER);
      text( contigStrain, getX1()-1, (getY1()+getY2())/2);
    }
    else 
    {
      float h = getY2()-getY1();
      if( h <= 5.0 )
        textSize(5.0);
      else if( h >= 20 )
        textSize( 18.0);
      else
        textSize( h );
    
      fill(175, 175, 175);
      textAlign(RIGHT, CENTER);
      text( contigStrain, getX1()-1, (getY1()+getY2())/2);
    }
  }
  //------------------------------------------END DRAW METHODS--------------------------------------------------
  //------------------------------------------INTERACTIVITY METHODS-----------------------------------------------------
  void highlightGene( int i )
  {
    genes[i].drawHighlightOnly();
  }
  
  void flip()
  {
    //bool isFlipped = true; 
     //for( int i = 0; i < genes.length; i++)
     //{
       //genes[i].flip();bbbbb
     //}
     
     //float temp = dynMaxNT.value;
     //dynMaxNT.target( dynMinNT.value );
     //dynMinNT.target( temp );
     //updateGenePositionAfterTargeting( c1.x.target, c1.y.value, c1.x.target, c2.y.value, dynMinNT.value, dynMaxNT.value);

  }
  
  //------------------------------------------END INTERACTIVITY METHODS-------------------------------------------------
  //------------------------------------------ANIMATION METHODS--------------------------------------------------
  void targetX1(float newX1)
  {
    this.target( newX1, c1.y.target, c2.x.target, c2.y.target, dynMaxNT.target );
  }
  
  void targetY1(float newY1)
  {
    this.target( c1.x.target, newY1, c2.x.target, c2.y.target, dynMaxNT.target );
  }
  
  void targetX2(float newX2)
  {
    this.target( c1.x.target, c1.y.target, newX2, c2.x.target, dynMaxNT.target ); //used to be value
  }
  
  void targetY2(float newY2)
  {
    this.target( c1.x.target, c1.y.target, c2.x.target, newY2, dynMaxNT.target );
  }
  
  void targetMaxNT(int newMaxNT)
  {
    this.target( c1.x.target, c1.y.target, c2.x.target, c2.y.target, (float) newMaxNT );
  }
  
  void target( float newX1, float newY1, float newX2, float newY2 )
  {
    this.target( newX1, newY1, newX2, newY2, dynMaxNT.target);
  }
  
  void target (float newX1, float newY1, float newX2, float newY2, float newMaxNT)
  {
    super.target( newX1, newY1, newX2, newY2 );
    
    dynMaxNT.target( newMaxNT );
    
    updateGenePositionAfterTargeting( newX1, newY1, newX2, newY2, dynMinNT.value, newMaxNT ); //note the insert of dynMinNT
  }
  
  void updateGenePositionAfterTargeting( float newX1, float newY1, float newX2, float newY2,  float newMinNT, float newMaxNT)
  {
    for(int i = 0; i < genes.length; i++)
    {
      float gX1 = calculateGeneX1( genes[i].getStart(), genes[i].getStop(), newMinNT, newMaxNT, newX1, newX2  ); 
      float gX2 = calculateGeneX2( genes[i].getStart(), genes[i].getStop(), newMinNT, newMaxNT , newX1, newX2 ); 
      float gY1 = calculateGeneY1( newY1, newY2 );
      float gY2 = calculateGeneY2( newY1, newY2 );
      genes[i].target( gX1, gY1, gX2, gY2 );
    }
  }
  
  boolean isTargeting()
  {
    return super.isTargeting() || dynMaxNT.isTargeting(); 
  }
  
  void update()
  {
   super.update();
   
   if( dynMaxNT.isTargeting() )
     dynMaxNT.update();
  }
  //---------------------------------------END ANIMATION METHODS-------------------------------------------------
  
  //----------------------------------------------INTERACTIVITY METHODS------------------------------------------
  
  boolean isOver( float x, float y )
  {
    return ( x >= (getX1() - 5) && x <= (getX2() + 5)  && y >= (getY1()-10) && y <= (getY2()+10) );
  }
  //-------------------------------------------END INTERACTIVITY METHODS-----------------------------------------
  
  //--------------------------------------------SETTERS----------------------------------------------------------
  
  void assignGeneColors( int geneIdx, int fillColor, int highlightColor )
  {
    genes[geneIdx].setColors( fillColor, highlightColor );
  }
  
  void assignGeneColor( int geneIdx, int fillColor )
  {
    genes[geneIdx].setColor( fillColor );
  }

  //----------------------------------------END SETTERS----------------------------------------------------------
  
  //--------------------------------------------GETTERS----------------------------------------------------------
  int getStop()
  {
    //find stop.. in this case, last gene
    int maxStop = 0;
    for(int i = 0; i < genes.length; i++)
    {
      if( genes[i].getGreatestNT() > maxStop )
        maxStop = genes[i].getGreatestNT();
    }
    
    return maxStop;
  }
  
  int getMaxNT()
  {
    return (int) dynMaxNT.value;
  }
  
  Gene getGene( float x, float y )
  {
    //Gene g = null;
    for(int i = 0; i < genes.length; i++)
    {
      if( genes[i].isOver( x, y ) )
      {
        return genes[i];//g = genes[i];
      }
    }
    
    return null;//g;
  }
  
  Gene getGene(int i)
  {
    if( i >= genes.length )
      return null;
    return genes[i];
  }
  
  int getNumberOfGenes()
  {
    return genes.length;
  }
  
  //-------------------------------------------END GETTERS-------------------------------------------------------
  //-------------------------------------------UTILITY METHODS---------------------------------------------------
  String toString()
  {
    return "" + contigId;
  }
  
  int compareTo( Object o )
  {
    Contig other = (Contig) o;
    if( genes.length != other.getNumberOfGenes() )
      return -1;

    //look to see if it has an identical gene order
    int identicalGenes = 0;
    for(int i = 0 ; i < genes.length; i++)
    {
      if( genes[i].equals( (Gene) other.getGene(i )) );
        identicalGenes++;
    }
    
    if( identicalGenes == genes.length )
    {
      println( "identical" );
      return 0;
    }
    
    identicalGenes = 0;
    for(int i = 0 ; i < genes.length; i++)
    {
      if( genes[i].equals( (Gene) other.getGene( genes.length-1-i) ))
        identicalGenes++;
    }
    
    if( identicalGenes == genes.length )
      return 0;
     
    return -1;
    //determine percent of genes in this that are in the same order in other- looking at forward and reverse orders
    
    
  }
 //-------------------------------------------UTILITY METHODS---------------------------------------------------
}

